# frozen_string_literal: true

module QA
  RSpec.describe 'Manage', :skip_live_env, requires_admin: 'creates users and instance OAuth application',
    product_group: :authentication_and_authorization do
    let!(:user) { Resource::User.fabricate_via_api! }
    let(:oidc_consumer_name) { 'gitlab-oidc-consumer' }
    let(:oidc_consumer_host) { "http://#{oidc_consumer_name}.#{Runtime::Env.running_in_ci? ? 'test' : 'bridge'}" }
    let(:instance_oauth_app) do
      Resource::InstanceOauthApplication.fabricate! do |application|
        application.redirect_uri = "#{oidc_consumer_host}/users/auth/openid_connect/callback"
        application.scopes = %w[openid profile email]
      end
    end

    after do
      instance_oauth_app.remove_via_api!
      remove_gitlab_service(oidc_consumer_name)
    end

    # The host GitLab instance with address Runtime::Scenario.gitlab_address is the OIDC idP - OIDC application will be
    # created here.
    # GitLab instance stood up in docker with address gitlab-oidc-consumer.test (or gitlab-oidc-consumer.bridge) is
    # the consumer - The GitLab OIDC Login button will be displayed here.
    describe 'OIDC' do
      it(
        'creates GitLab OIDC application and uses it to login',
        testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/405137',
        quarantine: {
          only: { pipeline: :nightly },
          type: :investigating,
          issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/408317'
        }
      ) do
        instance_oauth_app

        Page::Main::Menu.perform(&:sign_out_if_signed_in)

        app_id = instance_oauth_app.application_id
        app_secret = instance_oauth_app.application_secret

        consumer_gitlab_service = run_gitlab_service(name: oidc_consumer_name, app_id: app_id, app_secret: app_secret)

        wait_for_service(consumer_gitlab_service)

        page.visit oidc_consumer_host

        expect(page.driver.current_url).to include(oidc_consumer_host)

        Page::Main::Login.perform(&:sign_in_with_oidc)

        expect(page.driver.current_url).to include(Runtime::Scenario.gitlab_address)

        Flow::Login.sign_in(as: user)

        expect(page.driver.current_url).to include(oidc_consumer_host)

        Page::Dashboard::Welcome.perform do |welcome|
          expect(welcome).to have_welcome_title("Welcome to GitLab")
        end
      end

      def run_gitlab_service(name:, app_id:, app_secret:)
        Service::DockerRun::Gitlab.new(
          image: Runtime::Env.release,
          name: name,
          omnibus_config: omnibus_configuration(app_id: app_id, app_secret: app_secret)).tap do |gitlab|
          gitlab.login
          gitlab.pull
          gitlab.register!
        end
      end

      def remove_gitlab_service(name)
        Service::DockerRun::Gitlab.new(name: name).remove!
      end

      def wait_for_service(service)
        Support::Waiter.wait_until(max_duration: 900, sleep_interval: 5, raise_on_failure: true) do
          service.health == "healthy"
        end
      end

      def omnibus_configuration(app_id:, app_secret:)
        <<~OMNIBUS
          gitlab_rails['initial_root_password']='5iveL\!fe';
          gitlab_rails['omniauth_enabled'] = true;
          gitlab_rails['omniauth_allow_single_sign_on'] = true;
          gitlab_rails['omniauth_block_auto_created_users'] = false;
          gitlab_rails['omniauth_providers'] = [
            {
              name: 'openid_connect',
              label: 'GitLab OIDC',
              args: {
                name: 'openid_connect',
                scope: ['openid','profile','email'],
                response_type: 'code',
                issuer: '#{Runtime::Scenario.gitlab_address}',
                discovery: false,
                uid_field: 'preferred_username',
                send_scope_to_token_endpoint: 'false',
                client_options: {
                  identifier: '#{app_id}',
                  secret: '#{app_secret}',
                  redirect_uri: '#{oidc_consumer_host}/users/auth/openid_connect/callback',
                  jwks_uri: '#{Runtime::Scenario.gitlab_address}/oauth/discovery/keys',
                  userinfo_endpoint: '#{Runtime::Scenario.gitlab_address}/oauth/userinfo',
                  token_endpoint: '#{Runtime::Scenario.gitlab_address}/oauth/token',
                  authorization_endpoint: '#{Runtime::Scenario.gitlab_address}/oauth/authorize'
                }
              }
            }
          ];
        OMNIBUS
      end
    end
  end
end
